About Philadelphia
Philadelphia, Pennsylvania’s largest city, is notable for its rich history, on display at the Liberty Bell, Independence Hall (where the Declaration of Independence and Constitution were signed) and other American Revolutionary sites. Also iconic are the steps of the Philadelphia Museum of Art, immortalized by Sylvester Stallone’s triumphant run in the film “Rocky.”
Data was provided by https://www.opendataphilly.org/
Crime Incidents
Crime incidents from the Philadelphia Police Department. Part I crimes include violent offenses such as aggravated assault, rape, arson, among others. Part II crimes include simple assault, prostitution, gambling, fraud, and other non-violent offenses.
This dataset previously had separate endpoints for various years and types of incidents. These have since been consolidated into a single dataset.
Loading and taking a look into the dataset
#install.packages("lubridate")
#install.packages("virid")
#install.packages("plotly")
#install.packages("tm")
#install.packages("wordcloud")
#install.packages("leaflet")
#install.packages("xts")
#install.packages("highcharter")
#install.packages("forecast")
library(data.table)
library(forecast)
library(knitr)
library(tseries)
library(dplyr)
library(ggplot2)
library(lubridate)
library(tidyr)
library(viridis)
library(plotly)
library(tm)
library(wordcloud)
library(RColorBrewer)
library(leaflet)
library(xts)
library(highcharter)
Data size and structure.
crime_data <- fread("philly_crime.csv", showProgress = FALSE)
dim(crime_data)
[1] 2692698 16
str(crime_data)
Classes ‘data.table’ and 'data.frame': 2692698 obs. of 16 variables:
$ the_geom : chr "0101000020E610000091CDD92B01CA52C0952201BCE8FA4340" "0101000020E61000001007E842D5C952C02EC046ABBDF94340" "0101000020E610000081BA799166CE52C0B30631C8C4F84340" "0101000020E6100000E140CC4E94CB52C08C7BFB8CEEF74340" ...
$ dispatch_time : chr "01:52:00" "01:52:00" "01:36:00" "01:26:00" ...
$ the_geom_webmercator: chr "0101000020110F000027DA0ADC46EA5FC1E0FB0B15418A5241" "0101000020110F000097C72A46FCE95FC1E10189BAF5885241" "0101000020110F00007DA9A475BEF15FC115D02801E2875241" "0101000020110F00009316A2A0F3EC5FC1A5E792B2F4865241" ...
$ objectid : int 40069885 40084126 40069893 40086032 40077029 40061230 40065620 40062106 40086022 40081265 ...
$ dc_dist : int 6 6 12 17 22 39 12 25 14 25 ...
$ psa : chr "1" "2" "4" "3" ...
$ dispatch_date_time : chr "2019-12-11 01:52:00" "2019-12-11 01:52:00" "2019-12-11 01:36:00" "2019-12-11 01:26:00" ...
$ dispatch_date : chr "2019-12-11" "2019-12-11" "2019-12-11" "2019-12-11" ...
$ cartodb_id : int 2688326 2676639 2688696 2674928 2649006 2619877 2667540 2632680 2674305 2676701 ...
$ hour_ : int 1 1 1 1 1 0 0 0 0 0 ...
$ dc_key :integer64 201906064387 201906064385 201912105504 201917056325 201922108803 201939105668 201912105489 201925099886 ...
$ location_block : chr "1000 BLOCK HAMILTON ST" "800 BLOCK MARKET ST" "1100 BLOCK S 53RD ST" "2200 BLOCK OAKFORD ST" ...
$ ucr_general : int 400 2600 600 800 1400 2600 1800 800 800 1500 ...
$ text_general_code : chr "Aggravated Assault No Firearm" "All Other Offenses" "Thefts" "Other Assaults" ...
$ point_x : num -75.2 -75.2 -75.2 -75.2 -75.2 ...
$ point_y : num 40 40 39.9 39.9 40 ...
- attr(*, ".internal.selfref")=<externalptr>
table(is.na(crime_data))
FALSE TRUE
43035999 47169
- Over 47k records have missing values.
- Deleting records having missing values.
crime_data<-na.omit(crime_data)
table(is.na(crime_data))
FALSE
42667440
Extract Month and Year from the dispatch_date_time attribute
crime_data$Month_Year <- format(as.POSIXct(strptime(crime_data$dispatch_date_time,"%Y-%m-%d %H:%M:%S",tz="GMT")) ,format = "%Y-%m")
crime <- as.data.frame(crime_data)
crime$Day <- day(crime$dispatch_date_time)
crime$Year <- factor(year(crime$dispatch_date_time), levels=2006:2019)
crime$Month <- factor(month(crime$dispatch_date_time), levels=1:12)
crime$dispatch_date <- as.Date(crime$dispatch_date)
Time Series plot of Philadelphia Crimes
Since the data is in a series of particular time periods or intervals, we are plotting time series to look at trends over years
by_date <- crime %>% group_by(dispatch_date) %>% summarise(Total = n())
tseries <- xts(by_date$Total, order.by=as.POSIXct(by_date$dispatch_date))
hchart(tseries, name = "Crimes") %>%
hc_add_theme(hc_theme_darkunica()) %>%
hc_credits(enabled = TRUE, text = "Data Source: https://www.opendataphilly.org/ ", style = list(fontSize = "12px")) %>%
hc_title(text = "Time Series plot of Philadelphia Crimes") %>%
hc_legend(enabled = TRUE)
Location with Most Crimes - Top 20
by_location <- crime %>% group_by(location_block) %>%
summarise(Total = n()) %>% arrange(desc(Total))
hchart(by_location[1:20,], "column", hcaes(x = location_block, y = Total, color = Total)) %>%
hc_colorAxis(stops = color_stops(n = 10, colors = c("#440321", "#21908C", "#FDE725"))) %>%
hc_add_theme(hc_theme_darkunica()) %>%
hc_title(text = "Locations with most Crimes - Top 20") %>%
hc_credits(enabled = TRUE, text = "Data Source: https://www.opendataphilly.org/", style = list(fontSize = "15px")) %>%
hc_legend(enabled = FALSE)
We can observe that 5200 BLOCK Frankford Ave has highest number of crimes recorded.
Month comparison for each year(2006 - 2019)
monthplot <- ggplot(crime, aes(Year)) +
geom_bar(fill="#FF8685") +
ggtitle("Month comparison for each year(2006 - 2019)") +
facet_wrap(~Month) +
theme(axis.text.x = element_text(angle=120))
gg2 <- ggplotly(monthplot)
gg2
Crimes by Hour, Day, Month and Year
by_hour <- crime %>%
group_by(hour_) %>%
dplyr::summarise(Total = n())
by_hour
ggplot(by_hour, aes(hour_, Total, color = hour_)) +
geom_line() +
ggtitle("Crimes By Hour") +
xlab("Hour of the Day") +
ylab("Total Crimes")

by_day <- crime %>%
group_by(Day) %>%
dplyr::summarise(Total = n())
by_day
ggplot(by_day, aes(Day, Total, color = Day)) +
geom_line() +
ggtitle("Crimes By Day") +
xlab("Day of the Month") +
ylab("Total Crimes")

by_month <- crime %>%
group_by(Month) %>%
dplyr::summarise(Total = n())
by_month$Percent <- by_month$Total/dim(crime)[1] * 100
by_month
ggplot(by_month, aes(Month, Total, fill = Month)) +
geom_bar(stat = "identity") +
ggtitle("Crimes By Month") +
xlab("Month") +
ylab("Count") +
theme(legend.position = "none")

by_year <- crime %>%
group_by(Year) %>%
dplyr::summarise(Total = n())
by_year$Percent <- by_year$Total/dim(crime)[1] * 100
by_year
ggplot(by_year, aes(Year, Total, fill = Year)) +
geom_bar(stat = "identity") +
ggtitle("Crimes By Year ") +
xlab("Year") + ylab("Count") +
theme(legend.position = "none")

by_hour_year <- crime %>%
group_by(Year,hour_) %>%
dplyr::summarise(Total = n())
ggplot(by_hour_year, aes(hour_, Total, color = Year)) +
geom_line(size = 1) +
ggtitle("Crimes By Year and Hour") +
xlab("Hour of the Day") +
ylab("Total Crimes")

by_hour_month <- crime %>%
group_by(Month,hour_) %>%
dplyr::summarise(Total = n())
ggplot(by_hour_month, aes(hour_, Total, color = Month)) +
geom_line(size = 1) +
ggtitle("Crimes By Month and Hour") +
xlab("Hour of the Day") +
ylab("Total Crimes")

by_month_day <- crime %>%
group_by(Month, Day) %>%
dplyr::summarise(Total = n())
ggplot(by_month_day, aes(Day, Total, color = Month)) +
geom_line(size = 2) +
ggtitle("Crimes By Month and Day") +
xlab("Day") +
ylab("Count")

by_month_year <- crime %>%
group_by(Year, Month) %>%
dplyr::summarise(Total = n())
ggplot(by_month_year, aes(Year, Month, fill = Total)) +
geom_tile(color = "white") +
ggtitle("Crimes By Year and Month") +
xlab("Year") +
ylab("Month")

Crimes by Code, Month and Year
by_code <- crime %>%
group_by(text_general_code) %>%
dplyr::summarise(Total = n()) %>%
arrange(desc(Total))
by_code[1:50,]
ggplot(by_code, aes(reorder(text_general_code, Total), Total)) +
geom_bar(stat = "identity") + coord_flip() +
scale_y_continuous(breaks = seq(0,450000,50000)) +
ggtitle("Crimes By Code") +
xlab("Crime Text Code") +
ylab("Total Crimes")

by_code_year <- crime %>% group_by(Year, text_general_code) %>%
dplyr::summarise(Total = n())
by_code_year[1:10,]
ggplot(by_code_year, aes(reorder(text_general_code, Total), Total, fill = Year)) +
geom_bar(stat = "identity") +
scale_y_continuous(breaks = seq(0,450000,50000)) +
coord_flip() + ggtitle("Crimes By Code and Year") +
xlab("Crime Text Code") +
ylab("Total Crimes")

by_code_month <- crime %>%
group_by(Month, text_general_code) %>%
dplyr::summarise(Total = n())
by_code_month[1:10,]
ggplot(by_code_month, aes(reorder(text_general_code, Total), Total, fill = Month)) +
geom_bar(stat = "identity") +
scale_y_continuous(breaks = seq(0,450000,50000)) +
coord_flip() +
ggtitle("Crimes By Code and Month") +
xlab("Crime Text Code") +
ylab("Total Crimes")

Crime Types
by_type <- crime %>% group_by(text_general_code) %>%
summarise(Total = n()) %>% arrange(desc(Total))
hchart(by_type, "column", hcaes(text_general_code, y = Total, color = Total)) %>%
hc_colorAxis(stops = color_stops(n = 10, colors = c("#440154", "#21908C", "#FDE725"))) %>%
hc_add_theme(hc_theme_darkunica()) %>%
hc_title(text = "Crime Types") %>%
hc_credits(enabled = TRUE, text = "Sources: Philadelphia Police Department", style = list(fontSize = "12px")) %>%
hc_legend(enabled = FALSE)
Some Top Crimes
plotcrime <- function(varcrime) {
crimes <- crime[crime$text_general_code == varcrime,]
crimes_by_date <- crimes %>% group_by(dispatch_date) %>% dplyr::summarise(Total = n())
crimes_by_date$dispatch_date <- as.Date(crimes_by_date$dispatch_date)
tseries <- xts(crimes_by_date$Total, order.by=as.POSIXct(crimes_by_date$dispatch_date))
hchart(tseries, name = "Crimes") %>%
hc_colorAxis(stops = color_stops(n = 10, colors = c("#440154", "#21908C", "#FDE725"))) %>%
hc_add_theme(hc_theme_darkunica()) %>%
hc_title(text = varcrime) %>%
hc_credits(enabled = TRUE, text = "Sources: Philadelphia Police Department", style = list(fontSize = "12px")) %>%
hc_legend(enabled = FALSE)
}
plotcrime("All Other Offenses")
plotcrime("Other Assaults")
plotcrime("Thefts")
plotcrime("Fraud")
plotcrime("Theft from Vehicle")
plotcrime("Vandalism/Criminal Mischief")
plotcrime("Narcotic / Drug Law Violations")
Crimes by District Police HeadQuarters and Police Service Area
table(crime$dc_dist)
1 2 3 4 5 6 7 8 9 12 14 15 16 17 18
55651 135720 104309 28986 37285 115681 51839 85616 102887 154996 145648 216992 89963 86901 132999
19 22 23 24 25 26 35 39 77 92
172160 157360 27117 197472 177079 102933 158319 121815 5695 1292
table(crime$psa)
1 2 3 4 A B C D E F G H I J K
584514 649986 525161 81467 44513 37164 34798 51656 52898 48318 47733 50549 45626 50883 51178
L M N O P Q R S T U V W X Y Z
41421 38498 42540 33614 43998 20938 25336 28468 9629 10757 2465 2584 6321 1958 1744
crime$dc_dist <- factor(crime$dc_dist)
by_dc <- crime %>% group_by(dc_dist) %>%
dplyr::summarise(Total = n()) %>%
dplyr::arrange(desc(Total))
by_dc_psa <- crime %>%
group_by(dc_dist, psa) %>%
dplyr::summarise(Total = n())
ggplot(by_dc, aes(reorder(dc_dist, -Total), Total)) +
geom_bar(stat = "identity") +
ggtitle("Crimes by District Police HeadQuarters") +
xlab("Police HQ") +
ylab("Total Crimes")

by_dc_top5 <- by_dc$dc_dist[1:5]
by_top5_dc <- subset(crime, dc_dist %in% by_dc$dc_dist[1:5])
by_top5_dc$dc_dist <- factor(by_top5_dc$dc_dist)
ggplot(by_top5_dc, aes(dc_dist, fill = psa)) +
geom_bar(position = "dodge") +
ggtitle("Crimes by District Police HeadQuarters - Top 5") +
xlab("Police HQ") +
ylab("Total Crimes")

ggplot(by_dc_psa, aes(dc_dist, psa, fill = Total)) +
geom_tile(color = "white") +
ggtitle("Crimes by District Police HeadQuarters and Police Service Area") +
xlab("District Police HeadQuarters") +
ylab("Police Service Area")

Top crime in every District Head Quarters and every Police Service Area
dc_by_crime <- crime %>%
group_by(dc_dist, text_general_code) %>%
dplyr::summarise(Total = n()) %>%
arrange(desc(Total)) %>% top_n(n = 1)
Selecting by Total
dc_by_crime <- as.data.frame(dc_by_crime)
dc_by_crime$dc_dist <- factor(dc_by_crime$dc_dist)
dc_by_crime$text_general_code <- factor(dc_by_crime$text_general_code)
ggplot(dc_by_crime, aes(dc_dist, Total, fill = text_general_code)) +
geom_bar(stat = "identity") +
ggtitle("Top Crime by District Police HeadQuarters") +
xlab("District Police HeadQuarters") +
ylab("Total")

crime_by_psa <- crime %>%
group_by(psa, text_general_code) %>%
dplyr::summarise(Total = n()) %>%
arrange(desc(Total)) %>% top_n(n = 1)
Selecting by Total
crime_by_psa <- as.data.frame(crime_by_psa)
crime_by_psa$psa <- factor(crime_by_psa$psa)
crime_by_psa$text_general_code <- factor(crime_by_psa$text_general_code)
head(crime_by_psa)
ggplot(crime_by_psa, aes(psa, Total, fill = text_general_code)) +
geom_bar(stat = "identity") +
ggtitle("Top crime in Every Police Service Area") +
xlab("Police Service Area") +
ylab("Total")

crime_by_dc_psa <- crime %>%
group_by(dc_dist, psa, text_general_code) %>%
dplyr::summarise(Total = n()) %>%
arrange(desc(Total)) %>% top_n(n = 1)
Selecting by Total
crime_by_dc_psa <- as.data.frame(crime_by_dc_psa)
crime_by_dc_psa$dc_dist <- factor(crime_by_dc_psa$dc_dist)
crime_by_dc_psa$text_general_code <- factor(crime_by_dc_psa$text_general_code)
ggplot(crime_by_dc_psa, aes(dc_dist, psa, fill = text_general_code)) +
geom_tile(color = "white") +
ggtitle("Top crime in Every Police Service Area and District Head Quarters") +
xlab("District Police HeadQuarters") +
ylab("Police Service Area")

- All other Offenses classification is most common among all the District HeadQuarters, Second being Other Assaults
- It would be interesting to see how these two have increased or decreased over the years
- All other Offenses classification is most common among all Police Service Areas
- Assaults is most common in District HQ 14
- Very interesting one is Thefts from Vehicle and motor vehicle recovery are the only crimes in District HQ 92.
- Also we can see that in District HQ 77 there is only one type of crime reported i.e. Thefts.
Predictive Model - ARIMA Model
Several explorations have pointed out that crime seems to be seasonal and we wanted to explore this with a time series. Assuming that seasonal trends might repeat themselves, we are exploring this using the forecast package and using linear regression to predict trends.
Crimes by month
We can clearly see a downward trend in overall crime rates and also the fact that there seem to be seasonal peaks and declines.
bymo <- crime_data[order(Month_Year), .N, by=Month_Year]
dts <- ts(bymo$N, start = c(2006,1), frequency = 12)
dts_decomp<-decompose(dts, "multiplicative")
plot(dts,ylab="Total Crimes", main = "Monthly crimes with trend")
lines(dts_decomp$time.series[,2], col="tomato")

How seasonal is the data?
This autocorrelation shows a very high correlation every 12 months.
Acf(dts, main = "ACF of crime")

Forecast with a linear model
The red line shows the model’s prediction against the actual numbers in black. The model seems quite close.
f_crime <- tslm(dts ~ trend + season)
ff_crime <- forecast(f_crime,level=c(99),h =12)
plot(ff_crime)
lines(fitted(ff_crime), col = "red")

Residuals from model
This shows the residuals
res <- residuals(ff_crime)
plot(res, ylab="Residuals",xlab="Year", main = "Residuals")

summary(res)
Min. 1st Qu. Median Mean 3rd Qu. Max.
-6396.44 -456.31 -24.36 0.00 529.46 1800.72
Predictions
Here are the predicted overall crime numbers.
Conclusion:
- There is decrease in overall crime in last 15 years
- Crimes are most during middle quarter of every year(May-August)
- Crimes are least during Winter season and highest during Summer season.
- Crimes are least around 6AM in the morning
- Crimes are most around 4PM in the evening
- There is common trend in crimes over the years
- All Other Offenses, Other Assults and Thefts are the top 3 Crimes
- Thefts have increased over the years
- Narcotic/Drug Law Violations have decreased over the years
- District Police Head Quarters coded 15, 24 and 25 have the highest number of crimes reported.
- Top Crime in every District Police Head Quarters : All other offenses, other assaults, thefts and theft from vehicle.
LS0tCnRpdGxlOiAiQ3JpbWUgRGF0YSBBbmFseXNpcyBhbmQgUHJlZGljdGlvbiIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyMjIEFib3V0IFBoaWxhZGVscGhpYQoKUGhpbGFkZWxwaGlhLCBQZW5uc3lsdmFuaWHigJlzIGxhcmdlc3QgY2l0eSwgaXMgbm90YWJsZSBmb3IgaXRzIHJpY2ggaGlzdG9yeSwgb24gZGlzcGxheSBhdCB0aGUgTGliZXJ0eSBCZWxsLCBJbmRlcGVuZGVuY2UgSGFsbCAod2hlcmUgdGhlIERlY2xhcmF0aW9uIG9mIEluZGVwZW5kZW5jZSBhbmQgQ29uc3RpdHV0aW9uIHdlcmUgc2lnbmVkKSBhbmQgb3RoZXIgQW1lcmljYW4gUmV2b2x1dGlvbmFyeSBzaXRlcy4gQWxzbyBpY29uaWMgYXJlIHRoZSBzdGVwcyBvZiB0aGUgUGhpbGFkZWxwaGlhIE11c2V1bSBvZiBBcnQsIGltbW9ydGFsaXplZCBieSBTeWx2ZXN0ZXIgU3RhbGxvbmXigJlzIHRyaXVtcGhhbnQgcnVuIGluIHRoZSBmaWxtIOKAnFJvY2t5LuKAnQoKRGF0YSB3YXMgcHJvdmlkZWQgYnkgaHR0cHM6Ly93d3cub3BlbmRhdGFwaGlsbHkub3JnLwoKIyMjIENyaW1lIEluY2lkZW50cwoKQ3JpbWUgaW5jaWRlbnRzIGZyb20gdGhlIFBoaWxhZGVscGhpYSBQb2xpY2UgRGVwYXJ0bWVudC4gUGFydCBJIGNyaW1lcyBpbmNsdWRlIHZpb2xlbnQgb2ZmZW5zZXMgc3VjaCBhcyBhZ2dyYXZhdGVkIGFzc2F1bHQsIHJhcGUsIGFyc29uLCBhbW9uZyBvdGhlcnMuIFBhcnQgSUkgY3JpbWVzIGluY2x1ZGUgc2ltcGxlIGFzc2F1bHQsIHByb3N0aXR1dGlvbiwgZ2FtYmxpbmcsIGZyYXVkLCBhbmQgb3RoZXIgbm9uLXZpb2xlbnQgb2ZmZW5zZXMuCgpUaGlzIGRhdGFzZXQgcHJldmlvdXNseSBoYWQgc2VwYXJhdGUgZW5kcG9pbnRzIGZvciB2YXJpb3VzIHllYXJzIGFuZCB0eXBlcyBvZiBpbmNpZGVudHMuIFRoZXNlIGhhdmUgc2luY2UgYmVlbiBjb25zb2xpZGF0ZWQgaW50byBhIHNpbmdsZSBkYXRhc2V0LgoKIyMjIyBMb2FkaW5nIGFuZCB0YWtpbmcgYSBsb29rIGludG8gdGhlIGRhdGFzZXQKCmBgYHtyfQojaW5zdGFsbC5wYWNrYWdlcygibHVicmlkYXRlIikKI2luc3RhbGwucGFja2FnZXMoInZpcmlkIikKI2luc3RhbGwucGFja2FnZXMoInBsb3RseSIpCiNpbnN0YWxsLnBhY2thZ2VzKCJ0bSIpCiNpbnN0YWxsLnBhY2thZ2VzKCJ3b3JkY2xvdWQiKQojaW5zdGFsbC5wYWNrYWdlcygibGVhZmxldCIpCiNpbnN0YWxsLnBhY2thZ2VzKCJ4dHMiKQojaW5zdGFsbC5wYWNrYWdlcygiaGlnaGNoYXJ0ZXIiKQojaW5zdGFsbC5wYWNrYWdlcygiZm9yZWNhc3QiKQpsaWJyYXJ5KGRhdGEudGFibGUpCmxpYnJhcnkoZm9yZWNhc3QpCmxpYnJhcnkoa25pdHIpCmxpYnJhcnkodHNlcmllcykKbGlicmFyeShkcGx5cikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGx1YnJpZGF0ZSkKbGlicmFyeSh0aWR5cikKbGlicmFyeSh2aXJpZGlzKQpsaWJyYXJ5KHBsb3RseSkKbGlicmFyeSh0bSkKbGlicmFyeSh3b3JkY2xvdWQpCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpsaWJyYXJ5KGxlYWZsZXQpCmxpYnJhcnkoeHRzKQpsaWJyYXJ5KGhpZ2hjaGFydGVyKQpgYGAKCiMjIyMgRGF0YSBzaXplIGFuZCBzdHJ1Y3R1cmUuCgpgYGB7cn0KY3JpbWVfZGF0YSA8LSBmcmVhZCgicGhpbGx5X2NyaW1lLmNzdiIsIHNob3dQcm9ncmVzcyA9IEZBTFNFKQpkaW0oY3JpbWVfZGF0YSkKc3RyKGNyaW1lX2RhdGEpCmBgYAoKYGBge3J9CnRhYmxlKGlzLm5hKGNyaW1lX2RhdGEpKQpgYGAKKiBPdmVyIDQ3ayByZWNvcmRzIGhhdmUgbWlzc2luZyB2YWx1ZXMuCiogRGVsZXRpbmcgcmVjb3JkcyBoYXZpbmcgbWlzc2luZyB2YWx1ZXMuCgpgYGB7cn0KY3JpbWVfZGF0YTwtbmEub21pdChjcmltZV9kYXRhKQp0YWJsZShpcy5uYShjcmltZV9kYXRhKSkKYGBgCiogTm8gbWlzc2luZyB2YWx1ZXMgbm93CgojIyMjIEV4dHJhY3QgTW9udGggYW5kIFllYXIgZnJvbSB0aGUgZGlzcGF0Y2hfZGF0ZV90aW1lIGF0dHJpYnV0ZQoKYGBge3J9CmNyaW1lX2RhdGEkTW9udGhfWWVhciA8LSBmb3JtYXQoYXMuUE9TSVhjdChzdHJwdGltZShjcmltZV9kYXRhJGRpc3BhdGNoX2RhdGVfdGltZSwiJVktJW0tJWQgJUg6JU06JVMiLHR6PSJHTVQiKSkgLGZvcm1hdCA9ICIlWS0lbSIpCmNyaW1lIDwtIGFzLmRhdGEuZnJhbWUoY3JpbWVfZGF0YSkKY3JpbWUkRGF5IDwtIGRheShjcmltZSRkaXNwYXRjaF9kYXRlX3RpbWUpCmNyaW1lJFllYXIgPC0gZmFjdG9yKHllYXIoY3JpbWUkZGlzcGF0Y2hfZGF0ZV90aW1lKSwgbGV2ZWxzPTIwMDY6MjAxOSkKY3JpbWUkTW9udGggPC0gZmFjdG9yKG1vbnRoKGNyaW1lJGRpc3BhdGNoX2RhdGVfdGltZSksIGxldmVscz0xOjEyKQpjcmltZSRkaXNwYXRjaF9kYXRlIDwtIGFzLkRhdGUoY3JpbWUkZGlzcGF0Y2hfZGF0ZSkKYGBgCgojIyMjIFRpbWUgU2VyaWVzIHBsb3Qgb2YgUGhpbGFkZWxwaGlhIENyaW1lcwoKU2luY2UgdGhlIGRhdGEgaXMgaW4gYSBzZXJpZXMgb2YgcGFydGljdWxhciB0aW1lIHBlcmlvZHMgb3IgaW50ZXJ2YWxzLCB3ZSBhcmUgcGxvdHRpbmcgdGltZSBzZXJpZXMgdG8gbG9vayBhdCB0cmVuZHMgb3ZlciB5ZWFycwpgYGB7cn0KYnlfZGF0ZSA8LSBjcmltZSAlPiUgZ3JvdXBfYnkoZGlzcGF0Y2hfZGF0ZSkgJT4lIHN1bW1hcmlzZShUb3RhbCA9IG4oKSkKdHNlcmllcyA8LSB4dHMoYnlfZGF0ZSRUb3RhbCwgb3JkZXIuYnk9YXMuUE9TSVhjdChieV9kYXRlJGRpc3BhdGNoX2RhdGUpKQpoY2hhcnQodHNlcmllcywgbmFtZSA9ICJDcmltZXMiKSAlPiUgCiAgaGNfYWRkX3RoZW1lKGhjX3RoZW1lX2Rhcmt1bmljYSgpKSAlPiUKICBoY19jcmVkaXRzKGVuYWJsZWQgPSBUUlVFLCB0ZXh0ID0gIkRhdGEgU291cmNlOiBodHRwczovL3d3dy5vcGVuZGF0YXBoaWxseS5vcmcvICIsIHN0eWxlID0gbGlzdChmb250U2l6ZSA9ICIxMnB4IikpICU+JQogIGhjX3RpdGxlKHRleHQgPSAiVGltZSBTZXJpZXMgcGxvdCBvZiBQaGlsYWRlbHBoaWEgQ3JpbWVzIikgJT4lCiAgaGNfbGVnZW5kKGVuYWJsZWQgPSBUUlVFKQpgYGAKIyMjIyBMb2NhdGlvbiB3aXRoIE1vc3QgQ3JpbWVzIC0gVG9wIDIwCgpgYGB7ciB3YXJuaW5nPUZBTFNFLCBmaWcud2lkdGg9OSwgZmlnLmhlaWdodD01LjV9CmJ5X2xvY2F0aW9uIDwtIGNyaW1lICU+JSBncm91cF9ieShsb2NhdGlvbl9ibG9jaykgJT4lIAogIHN1bW1hcmlzZShUb3RhbCA9IG4oKSkgJT4lIGFycmFuZ2UoZGVzYyhUb3RhbCkpCmhjaGFydChieV9sb2NhdGlvblsxOjIwLF0sICJjb2x1bW4iLCBoY2Flcyh4ID0gbG9jYXRpb25fYmxvY2ssIHkgPSBUb3RhbCwgY29sb3IgPSBUb3RhbCkpICU+JQogIGhjX2NvbG9yQXhpcyhzdG9wcyA9IGNvbG9yX3N0b3BzKG4gPSAxMCwgY29sb3JzID0gYygiIzQ0MDMyMSIsICIjMjE5MDhDIiwgIiNGREU3MjUiKSkpICU+JQogIGhjX2FkZF90aGVtZShoY190aGVtZV9kYXJrdW5pY2EoKSkgJT4lCiAgaGNfdGl0bGUodGV4dCA9ICJMb2NhdGlvbnMgd2l0aCBtb3N0IENyaW1lcyAtIFRvcCAyMCIpICU+JQogIGhjX2NyZWRpdHMoZW5hYmxlZCA9IFRSVUUsIHRleHQgPSAiRGF0YSBTb3VyY2U6IGh0dHBzOi8vd3d3Lm9wZW5kYXRhcGhpbGx5Lm9yZy8iLCBzdHlsZSA9IGxpc3QoZm9udFNpemUgPSAiMTVweCIpKSAlPiUKICBoY19sZWdlbmQoZW5hYmxlZCA9IEZBTFNFKQpgYGAKV2UgY2FuIG9ic2VydmUgdGhhdCA1MjAwIEJMT0NLIEZyYW5rZm9yZCBBdmUgaGFzIGhpZ2hlc3QgbnVtYmVyIG9mIGNyaW1lcyByZWNvcmRlZC4KCiMjIyMgTW9udGggY29tcGFyaXNvbiBmb3IgZWFjaCB5ZWFyKDIwMDYgLSAyMDE5KQpgYGB7ciB3YXJuaW5nPUZBTFNFLGZpZy53aWR0aD05LCBmaWcuaGVpZ2h0PTUuNX0KbW9udGhwbG90IDwtIGdncGxvdChjcmltZSwgYWVzKFllYXIpKSArIAogICAgZ2VvbV9iYXIoZmlsbD0iI0ZGODY4NSIpICsKICAgIGdndGl0bGUoIk1vbnRoIGNvbXBhcmlzb24gZm9yIGVhY2ggeWVhcigyMDA2IC0gMjAxOSkiKSArCiAgICBmYWNldF93cmFwKH5Nb250aCkgKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9MTIwKSkKZ2cyIDwtIGdncGxvdGx5KG1vbnRocGxvdCkKZ2cyCmBgYAojIyMgQ3JpbWVzIGJ5IEhvdXIsIERheSwgTW9udGggYW5kIFllYXIKCmBgYHtyIHdhcm5pbmc9RkFMU0V9CmJ5X2hvdXIgPC0gY3JpbWUgJT4lIAogIGdyb3VwX2J5KGhvdXJfKSAlPiUgCiAgZHBseXI6OnN1bW1hcmlzZShUb3RhbCA9IG4oKSkKYnlfaG91cgpnZ3Bsb3QoYnlfaG91ciwgYWVzKGhvdXJfLCBUb3RhbCwgY29sb3IgPSBob3VyXykpICsgCiAgZ2VvbV9saW5lKCkgKyAKICBnZ3RpdGxlKCJDcmltZXMgQnkgSG91ciIpICsgCiAgeGxhYigiSG91ciBvZiB0aGUgRGF5IikgKyAKICB5bGFiKCJUb3RhbCBDcmltZXMiKSAKCmJ5X2RheSA8LSBjcmltZSAlPiUgCiAgZ3JvdXBfYnkoRGF5KSAlPiUgCiAgZHBseXI6OnN1bW1hcmlzZShUb3RhbCA9IG4oKSkKYnlfZGF5CgpnZ3Bsb3QoYnlfZGF5LCBhZXMoRGF5LCBUb3RhbCwgY29sb3IgPSBEYXkpKSArIAogIGdlb21fbGluZSgpICsgCiAgZ2d0aXRsZSgiQ3JpbWVzIEJ5IERheSIpICsgCiAgeGxhYigiRGF5IG9mIHRoZSBNb250aCIpICsgCiAgeWxhYigiVG90YWwgQ3JpbWVzIikgCgpieV9tb250aCA8LSBjcmltZSAlPiUgCiAgZ3JvdXBfYnkoTW9udGgpICU+JSAKICBkcGx5cjo6c3VtbWFyaXNlKFRvdGFsID0gbigpKQoKYnlfbW9udGgkUGVyY2VudCA8LSBieV9tb250aCRUb3RhbC9kaW0oY3JpbWUpWzFdICogMTAwCmJ5X21vbnRoCgpnZ3Bsb3QoYnlfbW9udGgsIGFlcyhNb250aCwgVG90YWwsIGZpbGwgPSBNb250aCkpICsgCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsgCiAgZ2d0aXRsZSgiQ3JpbWVzIEJ5IE1vbnRoIikgKyAKICB4bGFiKCJNb250aCIpICsgCiAgeWxhYigiQ291bnQiKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCmJ5X3llYXIgPC0gY3JpbWUgJT4lIAogIGdyb3VwX2J5KFllYXIpICU+JSAKICBkcGx5cjo6c3VtbWFyaXNlKFRvdGFsID0gbigpKQpieV95ZWFyJFBlcmNlbnQgPC0gYnlfeWVhciRUb3RhbC9kaW0oY3JpbWUpWzFdICogMTAwCmJ5X3llYXIKCmdncGxvdChieV95ZWFyLCBhZXMoWWVhciwgVG90YWwsIGZpbGwgPSBZZWFyKSkgKyAKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogIGdndGl0bGUoIkNyaW1lcyBCeSBZZWFyICIpICsgCiAgeGxhYigiWWVhciIpICsgeWxhYigiQ291bnQiKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCgpieV9ob3VyX3llYXIgPC0gY3JpbWUgJT4lIAogIGdyb3VwX2J5KFllYXIsaG91cl8pICU+JQogIGRwbHlyOjpzdW1tYXJpc2UoVG90YWwgPSBuKCkpCgpnZ3Bsb3QoYnlfaG91cl95ZWFyLCBhZXMoaG91cl8sIFRvdGFsLCBjb2xvciA9IFllYXIpKSArIAogIGdlb21fbGluZShzaXplID0gMSkgKyAKICBnZ3RpdGxlKCJDcmltZXMgQnkgWWVhciBhbmQgSG91ciIpICsgCiAgeGxhYigiSG91ciBvZiB0aGUgRGF5IikgKyAKICB5bGFiKCJUb3RhbCBDcmltZXMiKSAKCmJ5X2hvdXJfbW9udGggPC0gY3JpbWUgJT4lIAogIGdyb3VwX2J5KE1vbnRoLGhvdXJfKSAlPiUgCiAgZHBseXI6OnN1bW1hcmlzZShUb3RhbCA9IG4oKSkKCmdncGxvdChieV9ob3VyX21vbnRoLCBhZXMoaG91cl8sIFRvdGFsLCBjb2xvciA9IE1vbnRoKSkgKyAKICBnZW9tX2xpbmUoc2l6ZSA9IDEpICsgCiAgZ2d0aXRsZSgiQ3JpbWVzIEJ5IE1vbnRoIGFuZCBIb3VyIikgKyAKICB4bGFiKCJIb3VyIG9mIHRoZSBEYXkiKSArIAogIHlsYWIoIlRvdGFsIENyaW1lcyIpIAoKYnlfbW9udGhfZGF5IDwtIGNyaW1lICU+JSAKICBncm91cF9ieShNb250aCwgRGF5KSAlPiUgCiAgZHBseXI6OnN1bW1hcmlzZShUb3RhbCA9IG4oKSkKCmdncGxvdChieV9tb250aF9kYXksIGFlcyhEYXksIFRvdGFsLCBjb2xvciA9IE1vbnRoKSkgKyAKICBnZW9tX2xpbmUoc2l6ZSA9IDIpICsgCiAgZ2d0aXRsZSgiQ3JpbWVzIEJ5IE1vbnRoIGFuZCBEYXkiKSArIAogIHhsYWIoIkRheSIpICsgCiAgeWxhYigiQ291bnQiKQoKCmJ5X21vbnRoX3llYXIgPC0gY3JpbWUgJT4lIAogIGdyb3VwX2J5KFllYXIsIE1vbnRoKSAlPiUgCiAgZHBseXI6OnN1bW1hcmlzZShUb3RhbCA9IG4oKSkKCmdncGxvdChieV9tb250aF95ZWFyLCBhZXMoWWVhciwgTW9udGgsIGZpbGwgPSBUb3RhbCkpICsgCiAgZ2VvbV90aWxlKGNvbG9yID0gIndoaXRlIikgKyAKICBnZ3RpdGxlKCJDcmltZXMgQnkgWWVhciBhbmQgTW9udGgiKSArIAogIHhsYWIoIlllYXIiKSArIAogIHlsYWIoIk1vbnRoIikgCmBgYAojIyMgQ3JpbWVzIGJ5IENvZGUsIE1vbnRoIGFuZCBZZWFyCmBgYHtyIHdhcm5pbmc9RkFMU0V9CmJ5X2NvZGUgPC0gY3JpbWUgJT4lIAogIGdyb3VwX2J5KHRleHRfZ2VuZXJhbF9jb2RlKSAlPiUgCiAgZHBseXI6OnN1bW1hcmlzZShUb3RhbCA9IG4oKSkgJT4lIAogIGFycmFuZ2UoZGVzYyhUb3RhbCkpCgpieV9jb2RlWzE6NTAsXQoKZ2dwbG90KGJ5X2NvZGUsIGFlcyhyZW9yZGVyKHRleHRfZ2VuZXJhbF9jb2RlLCBUb3RhbCksIFRvdGFsKSkgKyAKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKyBjb29yZF9mbGlwKCkgKyAgCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLDQ1MDAwMCw1MDAwMCkpICsgCiAgZ2d0aXRsZSgiQ3JpbWVzIEJ5IENvZGUiKSArIAogIHhsYWIoIkNyaW1lIFRleHQgQ29kZSIpICsgCiAgeWxhYigiVG90YWwgQ3JpbWVzIikKCmJ5X2NvZGVfeWVhciA8LSBjcmltZSAlPiUgZ3JvdXBfYnkoWWVhciwgdGV4dF9nZW5lcmFsX2NvZGUpICU+JSAKICBkcGx5cjo6c3VtbWFyaXNlKFRvdGFsID0gbigpKQoKYnlfY29kZV95ZWFyWzE6MTAsXQoKZ2dwbG90KGJ5X2NvZGVfeWVhciwgYWVzKHJlb3JkZXIodGV4dF9nZW5lcmFsX2NvZGUsIFRvdGFsKSwgVG90YWwsIGZpbGwgPSBZZWFyKSkgKyAKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsNDUwMDAwLDUwMDAwKSkgKyAKICBjb29yZF9mbGlwKCkgKyBnZ3RpdGxlKCJDcmltZXMgQnkgQ29kZSBhbmQgWWVhciIpICsgCiAgeGxhYigiQ3JpbWUgVGV4dCBDb2RlIikgKyAKICB5bGFiKCJUb3RhbCBDcmltZXMiKQoKCmJ5X2NvZGVfbW9udGggPC0gY3JpbWUgJT4lIAogIGdyb3VwX2J5KE1vbnRoLCB0ZXh0X2dlbmVyYWxfY29kZSkgJT4lIAogIGRwbHlyOjpzdW1tYXJpc2UoVG90YWwgPSBuKCkpCmJ5X2NvZGVfbW9udGhbMToxMCxdCmdncGxvdChieV9jb2RlX21vbnRoLCBhZXMocmVvcmRlcih0ZXh0X2dlbmVyYWxfY29kZSwgVG90YWwpLCBUb3RhbCwgZmlsbCA9IE1vbnRoKSkgKyAKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsNDUwMDAwLDUwMDAwKSkgKyAKICBjb29yZF9mbGlwKCkgKyAKICBnZ3RpdGxlKCJDcmltZXMgQnkgQ29kZSBhbmQgTW9udGgiKSArIAogIHhsYWIoIkNyaW1lIFRleHQgQ29kZSIpICsgCiAgeWxhYigiVG90YWwgQ3JpbWVzIikKYGBgCiMjIyBDcmltZSBUeXBlcwoKYGBge3Igd2FybmluZz1GQUxTRX0KYnlfdHlwZSA8LSBjcmltZSAlPiUgZ3JvdXBfYnkodGV4dF9nZW5lcmFsX2NvZGUpICU+JSAKICBzdW1tYXJpc2UoVG90YWwgPSBuKCkpICU+JSBhcnJhbmdlKGRlc2MoVG90YWwpKQpoY2hhcnQoYnlfdHlwZSwgImNvbHVtbiIsIGhjYWVzKHRleHRfZ2VuZXJhbF9jb2RlLCB5ID0gVG90YWwsIGNvbG9yID0gVG90YWwpKSAlPiUKICBoY19jb2xvckF4aXMoc3RvcHMgPSBjb2xvcl9zdG9wcyhuID0gMTAsIGNvbG9ycyA9IGMoIiM0NDAxNTQiLCAiIzIxOTA4QyIsICIjRkRFNzI1IikpKSAlPiUKICBoY19hZGRfdGhlbWUoaGNfdGhlbWVfZGFya3VuaWNhKCkpICU+JQogIGhjX3RpdGxlKHRleHQgPSAiQ3JpbWUgVHlwZXMiKSAlPiUKICBoY19jcmVkaXRzKGVuYWJsZWQgPSBUUlVFLCB0ZXh0ID0gIlNvdXJjZXM6IFBoaWxhZGVscGhpYSBQb2xpY2UgRGVwYXJ0bWVudCIsIHN0eWxlID0gbGlzdChmb250U2l6ZSA9ICIxMnB4IikpICU+JQogIGhjX2xlZ2VuZChlbmFibGVkID0gRkFMU0UpCmBgYAojIyMgU29tZSBUb3AgQ3JpbWVzIAoKYGBge3Igd2FybmluZz1GQUxTRX0KcGxvdGNyaW1lICA8LSBmdW5jdGlvbih2YXJjcmltZSkgewogIGNyaW1lcyA8LSBjcmltZVtjcmltZSR0ZXh0X2dlbmVyYWxfY29kZSA9PSB2YXJjcmltZSxdIAogIGNyaW1lc19ieV9kYXRlIDwtIGNyaW1lcyAlPiUgZ3JvdXBfYnkoZGlzcGF0Y2hfZGF0ZSkgJT4lIGRwbHlyOjpzdW1tYXJpc2UoVG90YWwgPSBuKCkpCiAgY3JpbWVzX2J5X2RhdGUkZGlzcGF0Y2hfZGF0ZSA8LSBhcy5EYXRlKGNyaW1lc19ieV9kYXRlJGRpc3BhdGNoX2RhdGUpCiAgdHNlcmllcyA8LSB4dHMoY3JpbWVzX2J5X2RhdGUkVG90YWwsIG9yZGVyLmJ5PWFzLlBPU0lYY3QoY3JpbWVzX2J5X2RhdGUkZGlzcGF0Y2hfZGF0ZSkpCiAgaGNoYXJ0KHRzZXJpZXMsIG5hbWUgPSAiQ3JpbWVzIikgJT4lIAogICAgaGNfY29sb3JBeGlzKHN0b3BzID0gY29sb3Jfc3RvcHMobiA9IDEwLCBjb2xvcnMgPSBjKCIjNDQwMTU0IiwgIiMyMTkwOEMiLCAiI0ZERTcyNSIpKSkgJT4lCiAgICBoY19hZGRfdGhlbWUoaGNfdGhlbWVfZGFya3VuaWNhKCkpICU+JQogICAgaGNfdGl0bGUodGV4dCA9IHZhcmNyaW1lKSAlPiUKICAgIGhjX2NyZWRpdHMoZW5hYmxlZCA9IFRSVUUsIHRleHQgPSAiU291cmNlczogUGhpbGFkZWxwaGlhIFBvbGljZSBEZXBhcnRtZW50Iiwgc3R5bGUgPSBsaXN0KGZvbnRTaXplID0gIjEycHgiKSkgJT4lCiAgICBoY19sZWdlbmQoZW5hYmxlZCA9IEZBTFNFKQp9CmBgYAoKYGBge3Igd2FybmluZz1GQUxTRSB9CnBsb3RjcmltZSgiQWxsIE90aGVyIE9mZmVuc2VzIikKYGBgCgpgYGB7ciB3YXJuaW5nPUZBTFNFfQpwbG90Y3JpbWUoIk90aGVyIEFzc2F1bHRzIikKYGBgCmBgYHtyIHdhcm5pbmc9RkFMU0V9CnBsb3RjcmltZSgiVGhlZnRzIikKYGBgCmBgYHtyIHdhcm5pbmc9RkFMU0V9CnBsb3RjcmltZSgiRnJhdWQiKQpgYGAKYGBge3Igd2FybmluZz1GQUxTRX0KcGxvdGNyaW1lKCJUaGVmdCBmcm9tIFZlaGljbGUiKQpgYGAKYGBge3Igd2FybmluZz1GQUxTRX0KcGxvdGNyaW1lKCJWYW5kYWxpc20vQ3JpbWluYWwgTWlzY2hpZWYiKQpgYGAKYGBge3Igd2FybmluZz1GQUxTRX0KcGxvdGNyaW1lKCJOYXJjb3RpYyAvIERydWcgTGF3IFZpb2xhdGlvbnMiKQpgYGAKIyMjIENyaW1lcyBieSBEaXN0cmljdCBQb2xpY2UgSGVhZFF1YXJ0ZXJzIGFuZCBQb2xpY2UgU2VydmljZSBBcmVhCmBgYHtyIHdhcm5pbmc9RkFMU0V9CnRhYmxlKGNyaW1lJGRjX2Rpc3QpCnRhYmxlKGNyaW1lJHBzYSkKCmNyaW1lJGRjX2Rpc3QgPC0gZmFjdG9yKGNyaW1lJGRjX2Rpc3QpCgpieV9kYyA8LSBjcmltZSAlPiUgZ3JvdXBfYnkoZGNfZGlzdCkgJT4lIAogIGRwbHlyOjpzdW1tYXJpc2UoVG90YWwgPSBuKCkpICU+JSAKICBkcGx5cjo6YXJyYW5nZShkZXNjKFRvdGFsKSkKCmJ5X2RjX3BzYSA8LSBjcmltZSAlPiUgCiAgZ3JvdXBfYnkoZGNfZGlzdCwgcHNhKSAlPiUgCiAgZHBseXI6OnN1bW1hcmlzZShUb3RhbCA9IG4oKSkKCmdncGxvdChieV9kYywgYWVzKHJlb3JkZXIoZGNfZGlzdCwgLVRvdGFsKSwgVG90YWwpKSArIAogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArIAogIGdndGl0bGUoIkNyaW1lcyBieSBEaXN0cmljdCBQb2xpY2UgSGVhZFF1YXJ0ZXJzIikgKyAKICB4bGFiKCJQb2xpY2UgSFEiKSArIAogIHlsYWIoIlRvdGFsIENyaW1lcyIpIApieV9kY190b3A1IDwtIGJ5X2RjJGRjX2Rpc3RbMTo1XQpieV90b3A1X2RjIDwtIHN1YnNldChjcmltZSwgZGNfZGlzdCAlaW4lIGJ5X2RjJGRjX2Rpc3RbMTo1XSkKYnlfdG9wNV9kYyRkY19kaXN0IDwtIGZhY3RvcihieV90b3A1X2RjJGRjX2Rpc3QpCgpnZ3Bsb3QoYnlfdG9wNV9kYywgYWVzKGRjX2Rpc3QsIGZpbGwgPSBwc2EpKSArIAogIGdlb21fYmFyKHBvc2l0aW9uID0gImRvZGdlIikgKyAKICBnZ3RpdGxlKCJDcmltZXMgYnkgRGlzdHJpY3QgUG9saWNlIEhlYWRRdWFydGVycyAtIFRvcCA1IikgKyAKICB4bGFiKCJQb2xpY2UgSFEiKSArIAogIHlsYWIoIlRvdGFsIENyaW1lcyIpIAoKZ2dwbG90KGJ5X2RjX3BzYSwgYWVzKGRjX2Rpc3QsIHBzYSwgZmlsbCA9IFRvdGFsKSkgKyAKICBnZW9tX3RpbGUoY29sb3IgPSAid2hpdGUiKSArIAogIGdndGl0bGUoIkNyaW1lcyBieSBEaXN0cmljdCBQb2xpY2UgSGVhZFF1YXJ0ZXJzIGFuZCBQb2xpY2UgU2VydmljZSBBcmVhIikgKyAKICB4bGFiKCJEaXN0cmljdCBQb2xpY2UgSGVhZFF1YXJ0ZXJzIikgKyAKICB5bGFiKCJQb2xpY2UgU2VydmljZSBBcmVhIikgCmBgYAojIyMgVG9wIGNyaW1lIGluIGV2ZXJ5IERpc3RyaWN0IEhlYWQgUXVhcnRlcnMgIGFuZCBldmVyeSBQb2xpY2UgU2VydmljZSBBcmVhCgpgYGB7ciB3YXJuaW5nPUZBTFNFfQpkY19ieV9jcmltZSA8LSBjcmltZSAgJT4lIAogIGdyb3VwX2J5KGRjX2Rpc3QsIHRleHRfZ2VuZXJhbF9jb2RlKSAlPiUgCiAgZHBseXI6OnN1bW1hcmlzZShUb3RhbCA9IG4oKSkgJT4lIAogIGFycmFuZ2UoZGVzYyhUb3RhbCkpICU+JSB0b3BfbihuID0gMSkKCmRjX2J5X2NyaW1lIDwtIGFzLmRhdGEuZnJhbWUoZGNfYnlfY3JpbWUpCmRjX2J5X2NyaW1lJGRjX2Rpc3QgPC0gZmFjdG9yKGRjX2J5X2NyaW1lJGRjX2Rpc3QpCmRjX2J5X2NyaW1lJHRleHRfZ2VuZXJhbF9jb2RlIDwtIGZhY3RvcihkY19ieV9jcmltZSR0ZXh0X2dlbmVyYWxfY29kZSkKCmdncGxvdChkY19ieV9jcmltZSwgYWVzKGRjX2Rpc3QsIFRvdGFsLCBmaWxsID0gdGV4dF9nZW5lcmFsX2NvZGUpKSArIAogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArIAogIGdndGl0bGUoIlRvcCBDcmltZSBieSBEaXN0cmljdCBQb2xpY2UgSGVhZFF1YXJ0ZXJzIikgKyAKICB4bGFiKCJEaXN0cmljdCBQb2xpY2UgSGVhZFF1YXJ0ZXJzIikgKyAKICB5bGFiKCJUb3RhbCIpIAoKY3JpbWVfYnlfcHNhIDwtIGNyaW1lICAlPiUgCiAgZ3JvdXBfYnkocHNhLCB0ZXh0X2dlbmVyYWxfY29kZSkgJT4lIAogIGRwbHlyOjpzdW1tYXJpc2UoVG90YWwgPSBuKCkpICU+JSAKICBhcnJhbmdlKGRlc2MoVG90YWwpKSAlPiUgdG9wX24obiA9IDEpCgpjcmltZV9ieV9wc2EgPC0gYXMuZGF0YS5mcmFtZShjcmltZV9ieV9wc2EpCmNyaW1lX2J5X3BzYSRwc2EgPC0gZmFjdG9yKGNyaW1lX2J5X3BzYSRwc2EpCmNyaW1lX2J5X3BzYSR0ZXh0X2dlbmVyYWxfY29kZSA8LSBmYWN0b3IoY3JpbWVfYnlfcHNhJHRleHRfZ2VuZXJhbF9jb2RlKQoKaGVhZChjcmltZV9ieV9wc2EpCmdncGxvdChjcmltZV9ieV9wc2EsIGFlcyhwc2EsIFRvdGFsLCBmaWxsID0gdGV4dF9nZW5lcmFsX2NvZGUpKSArIAogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArIAogIGdndGl0bGUoIlRvcCBjcmltZSBpbiBFdmVyeSBQb2xpY2UgU2VydmljZSBBcmVhIikgKyAKICB4bGFiKCJQb2xpY2UgU2VydmljZSBBcmVhIikgKyAKICB5bGFiKCJUb3RhbCIpCgoKY3JpbWVfYnlfZGNfcHNhIDwtIGNyaW1lICAlPiUgCmdyb3VwX2J5KGRjX2Rpc3QsIHBzYSwgdGV4dF9nZW5lcmFsX2NvZGUpICU+JSAKICBkcGx5cjo6c3VtbWFyaXNlKFRvdGFsID0gbigpKSAlPiUgCiAgYXJyYW5nZShkZXNjKFRvdGFsKSkgJT4lIHRvcF9uKG4gPSAxKQoKY3JpbWVfYnlfZGNfcHNhIDwtIGFzLmRhdGEuZnJhbWUoY3JpbWVfYnlfZGNfcHNhKQpjcmltZV9ieV9kY19wc2EkZGNfZGlzdCA8LSBmYWN0b3IoY3JpbWVfYnlfZGNfcHNhJGRjX2Rpc3QpCmNyaW1lX2J5X2RjX3BzYSR0ZXh0X2dlbmVyYWxfY29kZSA8LSBmYWN0b3IoY3JpbWVfYnlfZGNfcHNhJHRleHRfZ2VuZXJhbF9jb2RlKQoKZ2dwbG90KGNyaW1lX2J5X2RjX3BzYSwgYWVzKGRjX2Rpc3QsIHBzYSwgZmlsbCA9IHRleHRfZ2VuZXJhbF9jb2RlKSkgKyAKICBnZW9tX3RpbGUoY29sb3IgPSAid2hpdGUiKSArIAogIGdndGl0bGUoIlRvcCBjcmltZSBpbiBFdmVyeSBQb2xpY2UgU2VydmljZSBBcmVhIGFuZCBEaXN0cmljdCBIZWFkIFF1YXJ0ZXJzIikgKyAKICB4bGFiKCJEaXN0cmljdCBQb2xpY2UgSGVhZFF1YXJ0ZXJzIikgKyAKICB5bGFiKCJQb2xpY2UgU2VydmljZSBBcmVhIikKYGBgCiogQWxsIG90aGVyIE9mZmVuc2VzIGNsYXNzaWZpY2F0aW9uIGlzIG1vc3QgY29tbW9uIGFtb25nIGFsbCB0aGUgRGlzdHJpY3QgSGVhZFF1YXJ0ZXJzLCBTZWNvbmQgYmVpbmcgT3RoZXIgQXNzYXVsdHMKKiBJdCB3b3VsZCBiZSBpbnRlcmVzdGluZyB0byBzZWUgaG93IHRoZXNlIHR3byBoYXZlIGluY3JlYXNlZCBvciBkZWNyZWFzZWQgb3ZlciB0aGUgeWVhcnMKKiBBbGwgb3RoZXIgT2ZmZW5zZXMgY2xhc3NpZmljYXRpb24gaXMgbW9zdCBjb21tb24gYW1vbmcgYWxsIFBvbGljZSBTZXJ2aWNlIEFyZWFzCiogQXNzYXVsdHMgaXMgbW9zdCBjb21tb24gaW4gRGlzdHJpY3QgSFEgMTQKKiBWZXJ5IGludGVyZXN0aW5nIG9uZSBpcyBUaGVmdHMgZnJvbSBWZWhpY2xlIGFuZCBtb3RvciB2ZWhpY2xlIHJlY292ZXJ5IGFyZSB0aGUgb25seSBjcmltZXMgaW4gRGlzdHJpY3QgSFEgOTIuCiogQWxzbyB3ZSBjYW4gc2VlIHRoYXQgaW4gRGlzdHJpY3QgSFEgNzcgdGhlcmUgaXMgb25seSBvbmUgdHlwZSBvZiBjcmltZSByZXBvcnRlZCBpLmUuIFRoZWZ0cy4KCiMjIyBQcmVkaWN0aXZlIE1vZGVsIC0gQVJJTUEgTW9kZWwKClNldmVyYWwgZXhwbG9yYXRpb25zIGhhdmUgcG9pbnRlZCBvdXQgdGhhdCBjcmltZSBzZWVtcyB0byBiZSBzZWFzb25hbCBhbmQgd2Ugd2FudGVkIHRvIGV4cGxvcmUgdGhpcyB3aXRoIGEgdGltZSBzZXJpZXMuIEFzc3VtaW5nIHRoYXQgc2Vhc29uYWwgdHJlbmRzIG1pZ2h0IHJlcGVhdCB0aGVtc2VsdmVzLCB3ZSBhcmUgZXhwbG9yaW5nIHRoaXMgdXNpbmcgdGhlIGZvcmVjYXN0IHBhY2thZ2UgYW5kIHVzaW5nIGxpbmVhciByZWdyZXNzaW9uIHRvIHByZWRpY3QgdHJlbmRzLgoKIyMjIyBDcmltZXMgYnkgbW9udGgKV2UgY2FuIGNsZWFybHkgc2VlIGEgZG93bndhcmQgdHJlbmQgaW4gb3ZlcmFsbCBjcmltZSByYXRlcyBhbmQgYWxzbyB0aGUgZmFjdCB0aGF0IHRoZXJlIHNlZW0gdG8gYmUgc2Vhc29uYWwgcGVha3MgYW5kIGRlY2xpbmVzLgoKYGBge3J9CmJ5bW8gPC0gY3JpbWVfZGF0YVtvcmRlcihNb250aF9ZZWFyKSwgLk4sIGJ5PU1vbnRoX1llYXJdCmR0cyA8LSB0cyhieW1vJE4sIHN0YXJ0ID0gYygyMDA2LDEpLCBmcmVxdWVuY3kgPSAxMikKZHRzX2RlY29tcDwtZGVjb21wb3NlKGR0cywgIm11bHRpcGxpY2F0aXZlIikKcGxvdChkdHMseWxhYj0iVG90YWwgQ3JpbWVzIiwgbWFpbiA9ICJNb250aGx5IGNyaW1lcyB3aXRoIHRyZW5kIikKbGluZXMoZHRzX2RlY29tcCR0aW1lLnNlcmllc1ssMl0sIGNvbD0idG9tYXRvIikKYGBgCiMjIyMgU2Vhc29uYWwgY29tcG9uZW50IGV4dHJhY3RlZCBmcm9tIHRoZSB0aW1lc2VyaWVzLgpgYGB7cn0KcGxvdChkdHNfZGVjb21wKQpgYGAKIyMjIyBIb3cgc2Vhc29uYWwgaXMgdGhlIGRhdGE/ClRoaXMgYXV0b2NvcnJlbGF0aW9uIHNob3dzIGEgdmVyeSBoaWdoIGNvcnJlbGF0aW9uIGV2ZXJ5IDEyIG1vbnRocy4gCmBgYHtyfQpBY2YoZHRzLCBtYWluID0gIkFDRiBvZiBjcmltZSIpCmBgYAojIyMjIEZvcmVjYXN0IHdpdGggYSBsaW5lYXIgbW9kZWwKVGhlIHJlZCBsaW5lIHNob3dzIHRoZSBtb2RlbCdzIHByZWRpY3Rpb24gYWdhaW5zdCB0aGUgYWN0dWFsIG51bWJlcnMgaW4gYmxhY2suIFRoZSBtb2RlbCBzZWVtcyBxdWl0ZSBjbG9zZS4gCgpgYGB7cn0KZl9jcmltZSA8LSB0c2xtKGR0cyB+IHRyZW5kICsgc2Vhc29uKQpmZl9jcmltZSA8LSBmb3JlY2FzdChmX2NyaW1lLGxldmVsPWMoOTkpLGggPTEyKQpwbG90KGZmX2NyaW1lKQpsaW5lcyhmaXR0ZWQoZmZfY3JpbWUpLCBjb2wgPSAicmVkIikKYGBgCiMjIyMgUmVzaWR1YWxzIGZyb20gbW9kZWwKVGhpcyBzaG93cyB0aGUgcmVzaWR1YWxzCgpgYGB7cn0KcmVzIDwtIHJlc2lkdWFscyhmZl9jcmltZSkKcGxvdChyZXMsIHlsYWI9IlJlc2lkdWFscyIseGxhYj0iWWVhciIsIG1haW4gPSAiUmVzaWR1YWxzIikgCnN1bW1hcnkocmVzKQpgYGAKIyMjIyBQcmVkaWN0aW9ucwpIZXJlIGFyZSB0aGUgcHJlZGljdGVkIG92ZXJhbGwgY3JpbWUgbnVtYmVycy4gCgpgYGB7ciwgZWNobz1GQUxTRX0KZmZfY3JpbWUKYGBgCiMjIyBDb25jbHVzaW9uOgoKKiBUaGVyZSBpcyBkZWNyZWFzZSBpbiBvdmVyYWxsIGNyaW1lIGluIGxhc3QgMTUgeWVhcnMKKiBDcmltZXMgYXJlIG1vc3QgZHVyaW5nIG1pZGRsZSBxdWFydGVyIG9mIGV2ZXJ5IHllYXIoTWF5LUF1Z3VzdCkKKiBDcmltZXMgYXJlIGxlYXN0IGR1cmluZyBXaW50ZXIgc2Vhc29uIGFuZCBoaWdoZXN0IGR1cmluZyBTdW1tZXIgc2Vhc29uLgoqIENyaW1lcyBhcmUgbGVhc3QgYXJvdW5kIDZBTSBpbiB0aGUgbW9ybmluZwoqIENyaW1lcyBhcmUgbW9zdCBhcm91bmQgNFBNIGluIHRoZSBldmVuaW5nCiogVGhlcmUgaXMgY29tbW9uIHRyZW5kIGluIGNyaW1lcyBvdmVyIHRoZSB5ZWFycwoqIEFsbCBPdGhlciBPZmZlbnNlcywgT3RoZXIgQXNzdWx0cyBhbmQgVGhlZnRzIGFyZSB0aGUgdG9wIDMgQ3JpbWVzCiogVGhlZnRzIGhhdmUgaW5jcmVhc2VkIG92ZXIgdGhlIHllYXJzCiogTmFyY290aWMvRHJ1ZyBMYXcgVmlvbGF0aW9ucyBoYXZlIGRlY3JlYXNlZCBvdmVyIHRoZSB5ZWFycwoqIERpc3RyaWN0IFBvbGljZSBIZWFkIFF1YXJ0ZXJzIGNvZGVkIDE1LCAyNCBhbmQgMjUgaGF2ZSB0aGUgaGlnaGVzdCBudW1iZXIgb2YgY3JpbWVzIHJlcG9ydGVkLgoqIFRvcCBDcmltZSBpbiBldmVyeSBEaXN0cmljdCBQb2xpY2UgSGVhZCBRdWFydGVycyA6IEFsbCBvdGhlciBvZmZlbnNlcywgb3RoZXIgYXNzYXVsdHMsIHRoZWZ0cyBhbmQgdGhlZnQgZnJvbSB2ZWhpY2xlLgoK